home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
pick
/
pick2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-11
|
22KB
|
823 lines
/*
* Copyright 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* pick2.c: an openGL RGB, double buffered and overlay window example
* program to demonstrate picking in openGL.
*
* - LEFTMOUSE: move the polygons around a center
* - RIGHTMOUSE: use rubber band to pick polygons
* - Esc key: exit
*
* By Philip W. Ho
*/
/* Compile: cc -o pick2 pick2.c -lGL -lGLU -lXext -lX11 */
/* Usage: pick2 [nx] [ny] */
/* nx - no. of polygons in x direction
ny - no. of polygons in y direction */
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define TRUE 1
#define FALSE 0
Display *dpy; /* The X server connection */
Atom del_atom; /* WM_DELETE_WINDOW atom */
Window glwin, o_win=NULL; /* handle to the GL window */
XEvent event;
XWindowAttributes winattri;
unsigned long fore,back;
XGCValues values;
GC mygc;
long valuemask;
GLXContext cx,cx_o;
/* Data for polygon */
typedef struct {
int id;
float xyz[3];
} Grid;
typedef struct {
int id;
int type;
int nd;
int conn[4];
int colr;
float xyz[12];
} Elem;
int double_buffer = TRUE;
XColor green_pixel,green_exact;
int no_grid;
int no_elem;
int nx,ny;
int picking;
Elem *elem, *em;
Grid *grid, *gd;
#define pick_buffer_size 2000
GLuint pick_buffer[pick_buffer_size];
/* function declarations */
static void openwindow(char *);
static void resize_buffer(void);
static void clean_exit(void);
void initGL(void);
void orient(void);
void drawScene(void);
void drawPolys(void);
void DrawXorPolyline(int , XPoint *);
void gendata(int, int);
void reset_color(void );
void open_auxwin(void );
void clearbox(void );
void set_picking(XPoint *);
static float objmat[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
};
int xsize, ysize; /* current size-of-window keepers */
double scrnaspect; /* aspect ratio value */
int xpos, ypos, oxpos, oypos; /* old and new mouse position */
XPoint box[5];
int xup1,yup1;
int xup2,yup2;
main(argc,argv)
int argc;
char **argv;
{
int myExpose, myConfigure, myButtPress, myKeyPress;
int firsttime,myXor;
int needToDraw = 0; /* don't set this to true until
we get our first Expose event */
myExpose = myConfigure = myButtPress = myKeyPress = FALSE;
myXor = FALSE;
firsttime = 0;
if(argc == 3)
{
nx = atoi(argv[1]);
ny = atoi(argv[2]);
}
else
{
nx = 10;
ny = 10;
}
openwindow(argv[0]);
gendata(nx,ny);
picking = 0;
/* start out making the singlebuffer window be our current GL window */
initGL(); /* do GL init stuff */
/*
* The event loop.
*/
while (1) { /* standard logic: get event(s), process event(s) */
XEvent event;
KeySym keysym;
char buf[4];
/* this "do while" loop does the `get events' half of the "get events,
* process events" action of the infinite while. this is to ensure
* the event queue is always drained before the events that have come
* in are processed.
*/
do {
XNextEvent(dpy, &event);
switch (event.type) {
/* "Expose" events are sort of like "REDRAW" in gl-speak in
* terms of when a window becomes visible, or a previously
* invisible part becomes visible.
*/
case Expose: /* Exposures */
needToDraw = myExpose = TRUE;
if(o_win == NULL)
open_auxwin();
break;
case ButtonPress:
if( event.xbutton.button == Button3)
{
xup1 = event.xmotion.x;
yup1 = event.xmotion.y;
box[0].x = xup1;
box[0].y = yup1;
box[4].x = xup1;
box[4].y = yup1;
myXor = TRUE;
firsttime = TRUE;
}
if( event.xbutton.button == Button2)
{
reset_color();
drawScene();
}
break;
case ButtonRelease:
if( event.xbutton.button == Button3)
{
int xsz,ysz;
xup2 = event.xmotion.x;
yup2 = event.xmotion.y;
box[1].x = xup2;
box[1].y = yup1;
box[2].x = xup2;
box[2].y = yup2;
box[3].x = xup1;
myXor = FALSE;
xsz = abs(xup2-xup1);
ysz = abs(yup2-yup1);
if( xsz>0 && ysz>0)
{
DrawXorPolyline(5,box);
set_picking(box);
drawScene();
}
clearbox();
}
break;
/* "ConfigNotify" events are like "REDRAW" in terms of changes
* to a window's size or position.
*/
case ConfigureNotify: /* Resize GL manually */
xsize = event.xconfigure.width;
ysize = event.xconfigure.height;
needToDraw = myConfigure = TRUE;
break;
/* Wait for "MotionNotify" events so the queue doesn't fill up
*/
case MotionNotify:
if(myXor)
{
if(!firsttime)
DrawXorPolyline(5,box);
xup2 = event.xmotion.x;
yup2 = event.xmotion.y;
box[1].x = xup2;
box[1].y = yup1;
box[2].x = xup2;
box[2].y = yup2;
box[3].x = xup1;
box[3].y = yup2;
DrawXorPolyline(5,box);
firsttime = FALSE;
}
else
{
myButtPress = TRUE;
xpos = event.xmotion.x;
ypos = event.xmotion.y;
}
break;
/* "ClientMessage" is generated if the WM itself is being
* gunned down and sends an exit signal to any running prog.
*/
case ClientMessage:
if (event.xclient.data.l[0] == del_atom)
clean_exit();
break;
/* "KeyPress" events are those that would be generated before
* whenever queueing up any KEYBD key via qdevice.
*/
case KeyPress:
/* save out which unmodified key (i.e. the key was
* not modified w/something like "Shift", "Ctrl",
* or "Alt") got pressed for use below.
*/
XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
myKeyPress = TRUE;
break;
} /* end switch (event.type) */
} while (XPending(dpy)); /* end "do { } while".
* XPending() is like qtest()--it only
* tells you if there're any events
* presently in the queue. it does not
* disturb queue's contents in any way.
*/
/* On an "Expose" event, redraw the affected pop'd or de-iconized window
*/
if (myExpose) {
resize_buffer();
myExpose = FALSE; /* reset flag--queue now empty */
}
/* On a "ConfigureNotify" event, the GL window has either been moved or
* resized. Respond accordingly and then redraw its contents.
*/
if (myConfigure) {
oxpos = xpos;
oypos = ypos;
resize_buffer();
myConfigure = FALSE; /* reset flag--queue now empty */
}
if (needToDraw) {
drawScene();
needToDraw = FALSE;
}
/* On a keypress of Esc key, exit program.
*/
if (myKeyPress) {
if (keysym == XK_Escape)
clean_exit();
}
if (myButtPress) {
orient();
drawScene();
myButtPress = FALSE;
}
} /* end while(1) */
} /* end main */
static int attributeOverlay[] = { GLX_BUFFER_SIZE, 2,
GLX_LEVEL, 1,
GLX_GREEN_SIZE, 1,
None };
void open_auxwin()
{
XSetWindowAttributes swa;
XVisualInfo *vi_o;
Colormap cmap_o;
Window root;
unsigned int width,height,border,depth;
int xorig,yorig;
int status;
XGetGeometry(dpy,glwin, &root, &xorig, &yorig, &width, &height, &border,
&depth);
vi_o = glXChooseVisual(dpy, DefaultScreen(dpy), attributeOverlay);
if (vi_o == NULL) {
printf("Unable to obtain Overlay Buffered VISUAL(????)\n");
exit(0);
}
cmap_o = XCreateColormap(dpy, RootWindow(dpy, vi_o->screen),
vi_o->visual, AllocNone);
status = XAllocNamedColor(dpy,cmap_o,"green",&green_pixel,&green_exact);
if(status == 0) {
printf("could not allocate green pixel\n");
}
swa.colormap = cmap_o;
swa.border_pixel = green_pixel.pixel;
swa.border_pixel = BlackPixel(dpy,DefaultScreen(dpy));
/* express interest in events */;
swa.event_mask = StructureNotifyMask | ButtonPressMask | ExposureMask |
Button1MotionMask | KeyPressMask | ButtonReleaseMask |
Button3MotionMask;
o_win = XCreateWindow(dpy, glwin, 0, 0, width, height, 0, vi_o->depth,
InputOutput, vi_o->visual, CWBorderPixel|CWColormap,
&swa);
XSetWMColormapWindows(dpy, glwin, &o_win, 1);
XMapWindow(dpy, o_win);
back = BlackPixel(dpy,DefaultScreen(dpy));
fore = green_pixel.pixel;
values.background=0;
values.foreground = fore;
values.function = GXxor;
valuemask = GCFunction | GCBackground | GCForeground;
mygc = XCreateGC(dpy,o_win,valuemask,&values);
}
static int attributeList[] = { GLX_RGBA,
GLX_DEPTH_SIZE, 16,
GLX_DOUBLEBUFFER,
None };
static int attributeList2[] = { GLX_RGBA,
GLX_DEPTH_SIZE, 16,
GLX_DOUBLEBUFFER,
None };
static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}
XSizeHints Winhints; /* used to fix window size */
/* openwindow -
* establish connection to X server, get screen info, specify the
* attributes we want the WM to try to provide, and create the GL window
*/
static void openwindow(char *progname) {
XVisualInfo *vi;
Colormap cmap;
XSizeHints Winhints; /* used to fix window size */
XSetWindowAttributes swa;
int scrnnum; /* X screen number */
int xorig, yorig; /* window (upper-left) origin */
long scrnheight;
/* define window initial size */
xorig = 50; yorig = 40;
xsize = 600; ysize = 600;
scrnaspect = xsize / (double) ysize;
/* Connect to the X server and get screen info */
if ((dpy = XOpenDisplay(NULL)) == NULL) {
fprintf(stderr, "%s: cannot connect to X server %s\n",
progname, XDisplayName(NULL));
exit(1);
}
scrnnum = DefaultScreen(dpy);
scrnheight = DisplayHeight(dpy, scrnnum);
/* get an appropriate visual */
vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
if (vi == NULL) {
fprintf(stderr, "Unable to obtain visual Doublebuffered visual\n");
vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList2);
}
if (vi == NULL) {
printf("Unable to obtain Singlebuffered VISUAL(????)\n");
exit(0);
}
/* create a GLX context */
cx = glXCreateContext(dpy, vi, None, GL_TRUE);
/* create a colormap */
cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
vi->visual, AllocNone);
/* create a window */
swa.colormap = cmap;
swa.border_pixel = 0;
/* express interest in events */;
swa.event_mask = StructureNotifyMask | ButtonPressMask | ExposureMask |
Button1MotionMask | KeyPressMask | ButtonReleaseMask | Button3MotionMask;
glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
xorig, yorig, xsize, ysize,
0, vi->depth, InputOutput, vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa);
XMapWindow(dpy, glwin);
/* XGetWindowAttributes(dpy,glwin,&winattri); */
/* XGetWindowAttributes(dpy,o_win,&winattri); */
XIfEvent(dpy, &event, WaitForNotify, (char*)glwin);
/* connect the context to the window */
glXMakeCurrent(dpy, glwin, cx);
/* printf("Back = %d fore = %d\n",back,fore); */
if (!(glwin)) {
fprintf(stderr,"%s: couldn't create \"parent\" X window\n",progname);
exit(1);
}
/* define string that will show up in the window title bar (and icon) */
XStoreName(dpy, glwin, "Picking using overlay ");
/* specify the values for the Window Size Hints we want to enforce: this
* window's aspect ratio needs to stay at 1:1, constrain min and max
* window size, and specify the initial size of the window.
*/
Winhints.width = xsize; /* specify desired x/y size of window */
Winhints.height = ysize;
Winhints.min_width = xorig; /* define min and max */
Winhints.max_width = scrnheight-1; /* width and height */
Winhints.min_height = yorig;
Winhints.max_height = scrnheight-1;
Winhints.min_aspect.x = xsize; /* keep aspect to a xsize:ysize ratio */
Winhints.max_aspect.x = xsize;
Winhints.min_aspect.y = ysize;
Winhints.max_aspect.y = ysize;
Winhints.flags = USSize|PMaxSize|PMinSize|PAspect; /* set the */
XSetNormalHints(dpy, glwin, &Winhints); /* corresponding flags */
/* express interest in WM killing this app */
if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", True)) != None)
XSetWMProtocols(dpy, glwin, &del_atom, 1);
return ;
}
/* window has been moved or resized so update viewport & CTM stuff.
*/
static void resize_buffer() {
XSync(dpy, False); /* STILL NEED THIS????? *//* Need before GL reshape */
scrnaspect = xsize / (double) ysize;
glViewport(0, 0, xsize-1, ysize-1);
}
/* clean up before exiting
*/
static void clean_exit(void)
{
XCloseDisplay(dpy);
exit(0);
}
/* setup all necessary GL initialzation parameters.
*/
void initGL()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* gluPerspective(400.0, scrnaspect, 30.0, 1000.0); */
glOrtho(-0.5, 0.5, -0.5, 0.5, -12.0, 12.0);
glMatrixMode(GL_MODELVIEW);
}
void orient()
{
float dx, dy;
glPushMatrix();
dx = xpos-oxpos;
dy = oypos-ypos;
glLoadIdentity();
glRotatef((float) (0.03*(xpos-oxpos)), 1.0, 0.0, 0.0);
glRotatef((float) (0.03*(oypos-ypos)), 0.0, 1.0, 0.0);
glMultMatrixf(objmat);
glGetFloatv(GL_MODELVIEW_MATRIX, objmat);
glPopMatrix();
}
void drawScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glMultMatrixf(objmat);
drawPolys();
glPopMatrix();
glFlush ();
glXSwapBuffers(dpy, glwin);
}
void drawPolys()
{
int i,j,k;
int id,col;
col = 1;
glColor3f(0.8, 0.8, 0.8);
em = elem;
for(i=0; i<no_elem; i++,em++)
{
if(picking)
{
id = i+101;
glPopName();
glPushName(id);
}
if(em->colr != col)
{
col = em->colr;
if(col == 2)
glColor3f(1.0, 0.0, 0.0);
else
glColor3f(0.8, 0.8, 0.8);
}
glBegin(GL_LINE_STRIP);
glVertex3fv(&em->xyz[0]);
glVertex3fv(&em->xyz[3]);
glVertex3fv(&em->xyz[6]);
glVertex3fv(&em->xyz[9]);
glVertex3fv(&em->xyz[0]);
glEnd();
}
}
void DrawXorPolyline(int num, XPoint *points)
{
XDrawLines(dpy, o_win, mygc, points, num, CoordModeOrigin);
XFlush(dpy);
return;
}
/* -------------------------------------------------------------------- */
void gendata(int nx, int ny)
{
int i,j,k,count;
int i1,i2,jj,kk,id;
float dx,dy;
float x,y,z;
float xx,yy;
int nxny;
int memsize;
no_grid = (nx+1)*(ny+1);
no_elem = nx*ny;
memsize = no_elem*sizeof(Elem);
elem = (Elem *)malloc(memsize);
memsize = no_grid*sizeof(Grid);
grid = (Grid *)malloc(memsize);
dx = 0.8/(float)nx;
dy = 0.8/(float)ny;
/* Generate grids */
count = 0;
z = 0.0;
gd = grid;
y = -0.4;
for(j=0; j < ny+1; j++)
{
x = -0.40;
for(i=0; i < nx+1; i++)
{
gd->id = count+1;
gd->xyz[0] = x;
gd->xyz[1] = y;
gd->xyz[2] = z;
count++;
gd++;
x += dx;
}
y += dy;
}
/* Generate elements */
count=0;
em = elem;
for(j=0; j < ny; j++)
{
jj = j*(nx+1);
for(i=0; i < nx; i++)
{
em->id = count+1;
em->type = 0;
em->nd = 4;
i1 = jj + i;
i2 = i1 + 1;
em->conn[0] = i1;
em->conn[1] = i2;
em->conn[2] = i2+(nx+1);
em->conn[3] = i1+(nx+1);
em->colr = 1; /* 1 for white color, later on change to
something elese */
em++;
count++;
}
}
em = elem;
for(i=0; i<no_elem; i++,em++)
{
xx = yy =0.0;
for(j=0; j<4; j++)
{
id = em->conn[j];
xx += (grid+id)->xyz[0];
yy += (grid+id)->xyz[1];
}
xx = xx*0.25;
yy = yy*0.25;
for(j=0,k=0; j<4; j++,k+=3)
{
id = em->conn[j];
x = (grid+id)->xyz[0];
y = (grid+id)->xyz[1];
z = (grid+id)->xyz[2];
dx = (xx -x)*0.3 ;
dy = (yy -y)*0.3 ;
em->xyz[k] = x + dx;
em->xyz[k+1] = y + dy;
em->xyz[k+2] = z;
}
}
/* write data out to file */
/*
printf("GRID data\n");
gd = grid;
for(i=0 ;i< no_grid; i++)
{
printf("%6d %15.4f %15.4f %15.4f\n",
gd->id, gd->xyz[0], gd->xyz[1], gd->xyz[2]);
gd++;
}
printf("ELEMENT data\n");
em = elem;
for(i=0; i<no_elem; i++)
{
printf("%6d %6d %6d %6d %6d %6d %6d %6d %6d\n",
em->id, em->conn[0], em->conn[1], em->conn[2], em->conn[3]);
em++;
}
*/
}
void reset_color()
{
int i,j;
em = elem;
for(i=0; i<no_elem; i++,em++)
em->colr = 1;
for(i=0; i<16; i++)
objmat[i] = 0.0;
objmat[0] = 1.0;
objmat[5] = 1.0;
objmat[10] = 1.0;
objmat[15] = 1.0;
values.background=0;
values.foreground = 0;
values.function = GXcopy;
valuemask = GCFunction | GCBackground | GCForeground;
mygc = XCreateGC(dpy,o_win,valuemask,&values);
XFillRectangle(dpy,o_win,mygc,0,0,xsize,ysize);
values.background=0;
values.foreground = fore;
values.function = GXxor;
valuemask = GCFunction | GCBackground | GCForeground;
mygc = XCreateGC(dpy,o_win,valuemask,&values);
}
void set_picking(XPoint *box)
{
int hits,i,j,items,indx;
int z1,z2,id;
float x1,x2,y1,y2;
picking = 1;
glSelectBuffer(pick_buffer_size, pick_buffer);
glRenderMode(GL_SELECT);
glInitNames();
glLoadName(0);
x1 = (float)box[0].x/xsize - 0.5;
x2 = (float)box[1].x/xsize - 0.5;
y1 = (float)(ysize-box[0].y)/ysize - 0.5;
y2 = (float)(ysize-box[2].y)/ysize - 0.5;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(x1,x2, y1,y2, -12.0, 12.0);
glMatrixMode(GL_MODELVIEW);
drawScene();
picking = 0;
reset_color();
hits = glRenderMode(GL_RENDER);
indx = 0;
for(i=0; i<hits; i++)
{
items = pick_buffer[indx++];
z1 = pick_buffer[indx++];
z2 = pick_buffer[indx++];
for(j=0; j<items; j++)
{
id = pick_buffer[indx++] - 101;
(elem+id)->colr = 2;
}
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-0.5, 0.5, -0.5, 0.5, -12.0, 12.0);
glMatrixMode(GL_MODELVIEW);
drawScene();
}
void clearbox()
{
int i;
for(i=0; i<5; i++)
{
box[i].x = 0;
box[i].y = 0;
}
}